#pragma once

#include "BasicType.h"
#include "ShapeStyleDef.h"
#include "Character.h"
#include "ShapeDef.h"

namespace LightPlayer{

	class Edge{
	public:
		enum eEdgeType{
			eStraightEdge=0, eCurvedEdge
		};
	private:
		eEdgeType	m_Type;
		vec2		m_Delta;
		vec2		m_OffLineControl;
	public:

		Edge( vec2 Delta ){
			m_Type = eStraightEdge;
			m_Delta = Delta;
		}
		Edge( vec2 OffLineControl, vec2 Delta ){
			m_Type = eCurvedEdge;
			m_OffLineControl = OffLineControl;
			m_Delta = Delta;
		}
				eEdgeType		getType() const					{ return m_Type; }
		const	vec2&			getDelta() const				{ return m_Delta; }
		const	vec2&			getOffLineControl() const		{ return m_OffLineControl; }
	};

	class Path {
		// common definition
		FILLSTYLEARRAY*					m_pFillStyleArray;
		uint32							m_FillIndex;
		bool							m_isClockwise;
		bool							m_FillRightSide;
			// vectorial definition
		vec2							m_StartPos;
		array<Edge>						m_Edges;
			// triangulation definition
		bool							m_TriangulationSucceed;
		array<vec2>						m_triangles;		
		array<vec2>						m_UVs; // use for bitmap fill
			// use for render Bezier curve in shader
		array<vec2>						m_ExternalCurveTris;
		array<vec2>						m_InternalCurveTris;

		array<Path*>					m_holes;
	private: 
		void							fillCurveTriangles();
		void							fillUVs(const MATRIX& bitmapMatrix);
		FILLSTYLE*						getFillStyle()									{return m_pFillStyleArray ? &(m_pFillStyleArray->at(m_FillIndex)) : NULL; }
	public:
		void							getBorderResolved( array<vec2>& borders, 
															bool test_curve_inside = false, 
															bool exclude_last_if_equal_first = false,
															bool inverse_inside_curve = false ) const;

										Path();
		void							init();

		void							pushBackEdge( const Edge& edge );
		void							pushFrontEdge( const Edge& edge );

		void							setStartPos(const vec2& startPos)	{m_StartPos = startPos;}
		vec2							getStartPos() const;
		vec2							getEndPos() const;

		void							setFillStyleArray(FILLSTYLEARRAY* _array)		{m_pFillStyleArray = _array;}
		void							setFillIndex(uint32 index)						{m_FillIndex = index;}
		uint32							getFillIndex() const							{return m_FillIndex;}

		const array<Edge>&				getEdges()										{return m_Edges;}
		const array<vec2>&				getTris()										{return m_triangles;}
		const array<vec2>&				getUVs()										{return m_UVs;}
		const array<vec2>&				getExternalCurveTris()							{return m_ExternalCurveTris;}
		const array<vec2>&				getInternalCurveTris()							{return m_InternalCurveTris;}
		bool							isTriangulationSucceed()						{return m_TriangulationSucceed;}

		void							triangulate();
		bool							computeIsClockwise();
		void							setFillRightSide(bool _val)						{m_FillRightSide = _val;}		

		bool							isHole() const									{return (!( (m_isClockwise && m_FillRightSide) || (!m_isClockwise && !m_FillRightSide) ) );}
		bool							testIsHoleInside(const Path* holeToTest) const;
		void							addHole(Path* hole);
		const array<Path*>&				getHoles() const								{return m_holes;}
	};

	class  CharacterList;

	class Shape : public Character {
		uint16					m_CharacterId;
		SHAPE_DEFINITION		m_SwfShape;
		RECT					m_ShapeBounds;

		FILLSTYLEARRAY			m_FillStyles;
		LINESTYLEARRAY			m_LineStyles;

		array<Path>				m_Paths;
		array<Path>				m_Lines;
	protected:

		void					AddStraightEdgeToFilledPath( const vec2& StartPos,const vec2& EndPos, uint32 fill_index, bool is_right_side_filled = false );
		void					AddCurvedEdgeToFilledPath( const vec2& StartPos, const vec2& OffLineControl, const vec2& EndPos, uint32 fill_index, bool is_right_side_filled = false );
		void					AddStraightEdgeToLinePath( const vec2& StartPos,const vec2& EndPos, uint32 fill_index );
		void					AddCurvedEdgeToLinePath( const vec2& StartPos, const vec2& OffLineControl, const vec2& EndPos, uint32 fill_index );

		void					drawFilledPath(LightAbstractRenderer* pRenderer, SceneObject* pInstance);
		void					drawFilledPathTriangulate(LightAbstractRenderer* pRenderer, SceneObject* pInstance);
		void					drawLinePath(LightAbstractRenderer* pRenderer, SceneObject* pInstance);

	public:
		
		Shape();
		void init();
		void readFromStream(Stream* stream, int tag_shape = eDefineShape, CharacterList* pCharacterList = NULL, bool is_font_glyph = false );

				const RECT&			getBounds() const														{return m_ShapeBounds;}

		// character interface
		virtual	eCharacterType		getType() const															{return eShapeCharacter;}
		virtual uint16				getCharacterId() const													{return m_CharacterId;};
				void				setCharacterId(uint16 characterId)										{m_CharacterId = characterId;};
		virtual void				draw(LightAbstractRenderer* pRenderer, SceneObject* pInstance);
	};

};